/*************************************************************
 * @file              call_mgr.c
 * @brief
 *
 *
 * @version   Version
 * @author    SealedGhost
 * @data
 *************************************************************/

#include "call_mgr.h"
#include "ccl.h"
#include <string.h>



#include "contact.h"

	/** @addtogroup       通话管理
 *
 *   @{
 */



static CallTransaction CallTransactionVector[CALL_TRANSACTION_MAX_NUMBER]  = {0};
static uint8_t CallTransactionNumber  = 0;


/**@brief  生成通话记录
  *
  * @param transaction 生成记录所依赖的通话事务
  * @return void
  * @note
  */
static void CallMgr_GenerateCallLog(CallTransaction* transaction)
{
	 CallLogItem logItem;
	
Debug("Generate call log:%u,%u", transaction->id, transaction->val);		
	 logItem.who.phoneNumber  = transaction->id;
	 logItem.who.shipNumber   = transaction->val;
	 logItem.dir  = transaction->type;
	 logItem.isMiss  = transaction->state != CALL_CONNECT ? 1 : 0 ;        
	 memcpy(&(logItem.when), &(transaction->time), sizeof(transaction->time));
	 CallLog_Add(&logItem);
}



/**@brief 向通话事务向量中添加事务
  *
  *
  * @return void
  * @note
  */
bool static CallMgr_AddTransaction(CallTransaction* pTransaction)
{
	 if(CallTransactionNumber < CALL_TRANSACTION_MAX_NUMBER){
			memcpy(&CallTransactionVector[CallTransactionNumber++], pTransaction, sizeof(CallTransaction));
			return true;
		}
		else{
			  return false;
		}
}



/**@brief    添加通话事务
  *
  *
  * @return void
  * @note
  */
bool CallMgr_AddCallTransaction(CallTransaction* pTransaction)
{
	 int i  = 0;
	 for(; i < CallTransactionNumber; i++){
			 if(CallTransactionVector[i].id  == pTransaction->id){
					  CallTransactionVector[i].state  = pTransaction->state;
					  return true;
				}
		}

		return CallMgr_AddTransaction(pTransaction);
}



/**@brief  更新事务的通话状态
  *
  *
  * @return void
  * @note
  */
void CallMgr_UpdateTransactionState(uint32_t id, uint8_t newState)
{
	 int i  = 0;

	 for(; i < CallTransactionNumber; i++){
			 if(CallTransactionVector[i].id == id){
					 CallTransactionVector[i].state  = newState;
					 return ;
				}
		}
}



/**@brief     得到指定位置的事务
  *
  * @param     pos  通话事务向量中的位置（1 为基准）
  * @return   所得的通话事务
  * @note
  */
CallTransaction* CallMgr_GetCallTransaction(int pos)
{
	 if(pos <= CallTransactionNumber){
			 return &CallTransactionVector[pos-1];
		}
		else{
			 return 0;
		}
}



 /**@brief  得到指定id的事务
  *
  * @param phoneId 指定的id，也是呼号
  * @return 所得的通话事务
  * @note
  */
CallTransaction* CallMgr_GetCallTransactionById(uint32_t phoneId)
{
			int i  = 0;

			for(; i < CallTransactionNumber; i++){
					if(CallTransactionVector[i].id == phoneId){
						return &CallTransactionVector[i];
					}
			}

			return 0;
}



/**@brief   删除指定的通话事务
  *
  *
  * @return void
  * @note
  */
void CallMgr_DeleteCallTransaction(uint32_t id)
{
	int i  = 0;

	for(; i < CallTransactionNumber; i++){
		if(CallTransactionVector[i].id == id){					 
			int k  = 0;
			for(; k < CallTransactionNumber -i -1; k++)
			{
				memcpy( &(CallTransactionVector[i +k]), &(CallTransactionVector[i +1 +k]), sizeof(CallTransaction));
			}
		}

		CallTransactionNumber--;
	}
}



/**@brief    得到当前通话事务的数量
  *
  *
  * @return   通话事务数量
  * @note
  */
inline uint8_t CallMgr_GetCallTransactionNumber()
{
	 return CallTransactionNumber;
}




 /**@brief  本机呼叫
  *
  * @param phoneId  呼叫的呼号
  * @return 如果呼叫的号码存在于联系人列表则返回被呼船号。
  * @note
  */

uint32_t CallMgr_Call(uint32_t phoneId)
{


	CallTransaction newTransaction  = {0};
	LinkMan* man  = Contact_FindByPhoneId(phoneId);

	if(man){
		newTransaction.val  = man->shipNumber;
	}

	newTransaction.id  = phoneId;
	newTransaction.type  = CALL_DIR_OUT;
	newTransaction.state = CALL_MISS;
	SysTime_Get(&(newTransaction.time));
	 

	CallMgr_AddCallTransaction(&newTransaction);



	Debug("Start to Call %u", phoneId);

	/// 通知 CCL 发起呼叫，传入呼叫目标的呼号和本机的船号
	CCL_Call(phoneId, 0);


	return newTransaction.val;
}




 /**@brief  本机接通
  *
  * @param  phoneId 接通的呼号
  * @return void
  * @note
  */
void CallMgr_Connect(uint32_t phoneId)
{

	/** 如果除了本次接通的呼号对应的事物外，还存在处于接通状态的事物，则自动将那些事物做挂断处理 */
	 int i  = 0;
	 for(; i < CallTransactionNumber; i++){
		 if(CallTransactionVector[i].id  !=  phoneId  &&  CallTransactionVector[i].state  ==  CALL_CONNECT){                     
			 CallMgr_GenerateCallLog( &CallTransactionVector[i] );
			 CallMgr_DeleteCallTransaction(CallTransactionVector[i].id); 
			 break;
		 }
	 }
	
	 CallMgr_UpdateTransactionState(phoneId, CALL_CONNECT);
	 Debug("Connect with %u", phoneId);
	
	 
	
	CCL_Connect(phoneId);
}



 /**@brief  本机挂断
  *
  * @param phoneId 挂断的呼号
  * @return void
  * @note
  */
void CallMgr_HangUp(uint32_t phoneId)
{
	 CallTransaction* pTransaction  = CallMgr_GetCallTransactionById(phoneId);
	 if(pTransaction){
Debug("Hang up %u", phoneId);             
			 CallMgr_GenerateCallLog(pTransaction);
			
			 CallMgr_DeleteCallTransaction(phoneId);
	 }
	 else{
Debug("Hang up but not match transaction\n");             
	 }
	 

		/// 通知 CCL 挂
	CCL_HangUp(phoneId);
}







 /**@brief 来电响应
  *
  *
  * @return void
  * @note
  */
LinkMan* OnCallIn(uint32_t phoneId, uint32_t boatNumber )
{
       CallTransaction newTransaction;


     LinkMan* man  = Contact_FindByPhoneId(phoneId);
     uint16_t  CurrCallNumber  = 0;

Debug("OnCallIn -- phone id:%u, boat number:%u", phoneId, boatNumber);


        newTransaction.id  = phoneId;
        newTransaction.type = CALL_DIR_IN;
        newTransaction.state = CALL_MISS;    
        SysTime_Get( &(newTransaction.time));

     /// 如果来电的是联系人，来电者船号用联系人中记录的船号
     if(man != 0){
                newTransaction.val  = man->shipNumber;
        }
        else{
             newTransaction.val  = boatNumber;
        }

if(! CallMgr_AddCallTransaction(&newTransaction)){
Debug("Add call transaction failed when call in");
        }


	return man;
}



 /**@brief  对方响铃响应
  *
  *
  * @return void
  * @note   如果拨打时没有从联系人列中中匹配到船号，则在此时得到被呼者的船号
  */
LinkMan* OnRing(uint32_t phoneId, uint32_t boatNumber)
{

     CallTransaction* pTransaction  = CallMgr_GetCallTransactionById(phoneId);
     LinkMan* man  = Contact_FindByPhoneId(phoneId);
//
     if(man != 0){
             boatNumber  = man->shipNumber;
        }

Debug("OnRing -- phone id:%u, boat number:%u", phoneId, boatNumber);

     if(pTransaction){
             if(pTransaction->val == 0){
                     pTransaction->val  = boatNumber;
                }
        }
        else{
Debug("Error!!!!!! OnRing but match none transaction");
            return 0;
        }

        return man;
        /// 响忙音
}



	/**@brief 对方接通响应
  *
  *
  * @return void
  * @note
  */
bool OnConnect(uint32_t phoneId, uint32_t boatNumber)
{
Debug("OnConnect");
    CallMgr_UpdateTransactionState(phoneId, CALL_CONNECT);
    
    return true;
}



	/**@brief  对方挂断响应
  *
  *
  * @return void
  * @note
  */
bool OnHangUp(uint32_t phoneId, uint32_t boatNumber)
{

    CallTransaction* pTransaction;

Debug("OnHangUp, id = %u", phoneId);		
    
    pTransaction  = CallMgr_GetCallTransactionById(phoneId);
    
    if(pTransaction){				
        CallMgr_GenerateCallLog(pTransaction);
    }
    else{
Debug("Error!!!!!!!!, Hang up but not match any call transaction");     
            return false;
    }

    CallMgr_DeleteCallTransaction(phoneId);
    
    return true;
}



	/**@brief  对方应答忙响应
  *
  *
  * @return void
  * @note
  */
bool OnTellBusy(uint32_t phoneId, uint32_t boatNumber)
{
    CallTransaction* pTransaction;
Debug("OnTellBusy:%u", phoneId);
    pTransaction  = CallMgr_GetCallTransactionById(phoneId);
    
    if(pTransaction){
        CallMgr_GenerateCallLog(pTransaction);
    }
    else{
Debug("Error!!!!!!!!, Tell busy but not match any call transaction");     
            return false;
    }
    CallMgr_DeleteCallTransaction(phoneId);
    
    return true;


/// 响对方忙提示音
}
	
	
	
	
	/**@brief   呼叫失败响应
  * 
  *
  * @return void
  * @note
  */
bool OnCallFail(uint32_t phoneId, uint32_t boatNumber)
{
    CallTransaction* pTransaction;
    
Debug("OnCallFail");
    
    pTransaction  = CallMgr_GetCallTransactionById(phoneId);
    if(pTransaction){
        CallMgr_GenerateCallLog(pTransaction);
    }
    else{
Debug("Error!!!!!!!!, Tell fail but not match any call transaction"); 
        return false;
    }
    CallMgr_DeleteCallTransaction(phoneId);
    
    return true;
}
	
	
	

#if 0
void CallMgr_DumpTransaction()
{
    int  i  = 0;

    Debug("Call transaction:");
    for(; i < CallTransactionNumber; i++){
        Debug("Call %s, phone id:%u, boat number %u, %s", CallTransactionVector[i].type == CALL_DIR_IN ? "in" : "out",
				                                          CallTransactionVector[i].id, CallTransactionVector[i].val,
				                                          CallTransactionVector[i].state == CALL_CONNECT ? "connect" : "not connect");
    }
}
#endif


/** @} */
